package com.wolfcode.audit.service.impl;

import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

import com.wolfcode.appointment.domain.BusServiceItem;
import com.wolfcode.appointment.enums.AuditEnum;
import com.wolfcode.appointment.enums.CarPackageEnum;
import com.wolfcode.appointment.mapper.BusServiceItemMapper;
import com.wolfcode.audit.domain.info.HistoricCommentInfo;
import com.wolfcode.audit.domain.vo.BusCarPackageAuditVo;
import com.wolfcode.audit.enums.PackageAuditEnum;
import com.wolfcode.common.core.domain.model.LoginUser;
import com.wolfcode.common.utils.DateUtils;
import com.wolfcode.common.utils.PageUtils;
import com.wolfcode.common.utils.SecurityUtils;
import com.wolfcode.flow.domain.BusBpmnInfo;
import com.wolfcode.flow.mapper.BusBpmnInfoMapper;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.engine.HistoryService;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Comment;
import org.activiti.engine.task.Task;
import org.activiti.image.impl.DefaultProcessDiagramGenerator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.wolfcode.audit.mapper.BusCarPackageAuditMapper;
import com.wolfcode.audit.domain.BusCarPackageAudit;
import com.wolfcode.audit.service.IBusCarPackageAuditService;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

/**
 * 套餐审核Service业务层处理
 * 
 * @author wolfcode
 * @date 2022-11-28
 */
@Service
public class BusCarPackageAuditServiceImpl implements IBusCarPackageAuditService 
{
    @Autowired
    private BusCarPackageAuditMapper busCarPackageAuditMapper;
    @Autowired
    private BusBpmnInfoMapper busBpmnInfoMapper;
    @Autowired
    private TaskService taskService;
    @Autowired
    private RuntimeService runtimeService;
    @Autowired
    private HistoryService historyService;
    @Autowired
    private RepositoryService repositoryService;
    @Autowired
    private BusServiceItemMapper busServiceItemMapper;
    /**
     * 查询套餐审核
     * 
     * @param id 套餐审核主键
     * @return 套餐审核
     */
    @Override
    public BusCarPackageAudit selectBusCarPackageAuditById(Long id)
    {
        return busCarPackageAuditMapper.selectBusCarPackageAuditById(id);
    }

    /**
     * 查询套餐审核列表
     * 
     * @param busCarPackageAudit 套餐审核
     * @return 套餐审核
     */
    @Override
    public List<BusCarPackageAudit> selectBusCarPackageAuditList(BusCarPackageAudit busCarPackageAudit)
    {
        return busCarPackageAuditMapper.selectBusCarPackageAuditList(busCarPackageAudit);
    }

    /**
     * 新增套餐审核
     * 
     * @param busCarPackageAudit 套餐审核
     * @return 结果
     */
    @Override
    public int insertBusCarPackageAudit(BusCarPackageAudit busCarPackageAudit)
    {
        busCarPackageAudit.setCreateTime(DateUtils.getNowDate());
        return busCarPackageAuditMapper.insertBusCarPackageAudit(busCarPackageAudit);
    }

    /**
     * 修改套餐审核
     * 
     * @param busCarPackageAudit 套餐审核
     * @return 结果
     */
    @Override
    public int updateBusCarPackageAudit(BusCarPackageAudit busCarPackageAudit)
    {
        return busCarPackageAuditMapper.updateBusCarPackageAudit(busCarPackageAudit);
    }

    /**
     * 批量删除套餐审核
     * 
     * @param ids 需要删除的套餐审核主键
     * @return 结果
     */
    @Override
    public int deleteBusCarPackageAuditByIds(Long[] ids)
    {
        return busCarPackageAuditMapper.deleteBusCarPackageAuditByIds(ids);
    }

    /**
     * 删除套餐审核信息
     * 
     * @param id 套餐审核主键
     * @return 结果
     */
    @Override
    public int deleteBusCarPackageAuditById(Long id)
    {
        return busCarPackageAuditMapper.deleteBusCarPackageAuditById(id);
    }

    /**
     * 我的代办
     * @return
     */
    @Override
    public List<BusCarPackageAudit> todoQuery(BusCarPackageAuditVo busCarPackageAuditVo) {
        // 校验
        // 1 获取套餐审核流程定义信息
        BusBpmnInfo busBpmnInfo = busBpmnInfoMapper.getByBpmnType(0);
        Assert.notNull(busBpmnInfo, "请先上传流程定义");
        // userid:101
        String userId = SecurityUtils.getUserId().toString();
        //2 查询任务列表
        List<Task> taskList = taskService.createTaskQuery()
                .processDefinitionKey(busBpmnInfo.getProcessDefinitionKey())
                .taskAssignee(userId)
                .list();
        if (CollectionUtils.isEmpty(taskList)) {
            return Collections.emptyList();
        }
        // ru_task---procIds
        Set<String> processInstanceIds = taskList.stream().map((task) ->
                task.getProcessInstanceId()).collect(Collectors.toSet());
        // ru_execution ---business_keys
        List<ProcessInstance> processInstances = runtimeService.createProcessInstanceQuery().
                processInstanceIds(processInstanceIds).list();
        List<String> businessKeys = processInstances.stream().map((processInstance) ->
                processInstance.getBusinessKey()).collect(Collectors.toList());
        PageUtils.startPage();
        // bus_car_package_audit--- 套餐信息
        List<BusCarPackageAudit> busCarPackageAudits = busCarPackageAuditMapper
                .selectBusCarPackageAuditListByBusinessKeys(businessKeys);
        return busCarPackageAudits;
    }

    /**
     * 套餐审核
     * @param auditVo
     */
    @Override
    @Transactional
    public void audit(BusCarPackageAuditVo auditVo) {
        // 校验
        // 1 获取套餐信息
        BusCarPackageAudit busCarPackageAudit = this.selectBusCarPackageAuditById(auditVo.getId());
        Assert.notNull(busCarPackageAudit, "非法参数");
        // 2 校验审核状态，审核中才允许审核
        Assert.state(PackageAuditEnum.AUDITING.ordinal() == busCarPackageAudit.getStatus(),
                "审核中的才允许审核");
        // 3 添加批注，完成，让流程往下走
        LoginUser loginUser = SecurityUtils.getLoginUser();
        Task task = taskService.createTaskQuery()
                .processInstanceId(busCarPackageAudit.getInstanceId()).singleResult();
        String auditLabel = auditVo.isAuditStatus() ? "同意" : "拒绝";
        String comment = loginUser.getUsername() + "[" + auditLabel + "]," + auditVo.getInfo();
        //String taskId 任务id
        //String processInstanceId 流程实例id
        //String message 批注信息
        taskService.addComment(task.getId(),busCarPackageAudit.getInstanceId(),comment);
        //String taskId
        //String variableName
        //Object value
        //设置流程变量（shopOwner,ru_task(task_def_key)）
        //shopOwner=false---拒绝根据bpmn图，直接结束事件
        //Unknown property used in expression: ${!shopOwner}
        // ru_task：taskDefinitionKey: shopOwner = true
        taskService.setVariable(task.getId(),task.getTaskDefinitionKey(),auditVo.isAuditStatus());
        taskService.complete(task.getId());
        // 4 判断同意还是拒绝
        // 假设同意
            // 看一下有没有下个任务
            // 没有下个任务，代表流程结束：更新一些审核状态，审核通过
            // 有下个任务，不处理
        // 假如拒绝，更新一些审核状态，审核拒绝
        // 4 根据审核状态（同意还是拒绝）更新套餐审核和服务单项的状态
        BusCarPackageAudit audit = new BusCarPackageAudit();
        BusServiceItem serviceItem = new BusServiceItem();
        if (auditVo.isAuditStatus()) {
            // 同意
            // 判断还有没有下一个任务，没有代表任务结束
            Task nextTask = taskService.createTaskQuery()
                    .processInstanceId(busCarPackageAudit.getInstanceId())
                    .singleResult();
            if (nextTask == null) {
                updateState(busCarPackageAudit,
                        audit, serviceItem,
                        PackageAuditEnum.PASS,
                        AuditEnum.PASS);
            }
        } else {
            // 拒绝
            updateState(busCarPackageAudit,
                    audit, serviceItem,
                    PackageAuditEnum.REJECT,
                    AuditEnum.REJECT);
        }
    }

    @Override
    public List<HistoricCommentInfo> listHistory(String instanceId) {
        Assert.notNull(instanceId,"非法参数");
        List<HistoricTaskInstance> taskInstances = historyService
                .createHistoricTaskInstanceQuery()
                .processInstanceId(instanceId)
                .orderByHistoricTaskInstanceEndTime()
                .asc()
                .list();

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        // 2 处理历史任务列表
        List<HistoricCommentInfo> historicCommentInfos = taskInstances
                .stream()
                .map((taskInstance -> {
                    HistoricCommentInfo historicCommentInfo = new HistoricCommentInfo();
                    // 任务名称
                    historicCommentInfo.setTaskName(taskInstance.getName());
                    // 开始时间
                    historicCommentInfo.setStartTime(sdf.format(taskInstance.getStartTime()));
                    // 结束时间
                    if (taskInstance.getEndTime() != null) {
                        historicCommentInfo.setEndTime(sdf.format(taskInstance.getEndTime()));
                    }
                    // 持续时间
                    if (taskInstance.getDurationInMillis() != null) {
//                String durationMills = DateUtils.getDatePoor(taskInstance.getEndTime(), taskInstance.getStartTime());
                        historicCommentInfo.setDurationInMillis(String.valueOf(taskInstance.getDurationInMillis()));
                    }
                    // 评论
                    // 评论设计有问题，应该设计到历史表中，不是再运行的时候，官方也意识到这一点
                    List<Comment> comments = taskService.getTaskComments(taskInstance.getId(),
                            "comment");
                    if (!CollectionUtils.isEmpty(comments)) {
                        historicCommentInfo.setComment(comments.get(0).getFullMessage());
                    }
                    return historicCommentInfo;
                })).collect(Collectors.toList());
        return historicCommentInfos;
    }

    /**
     * @param id 审核套餐id
     * @return
     */
    @Override
    public InputStream getProcessInputStream(Long id) {
        Assert.notNull(id,"非法参数");
        // 1 获取审核套餐
        BusCarPackageAudit busCarPackageAudit = selectBusCarPackageAuditById(id);
        Assert.notNull(busCarPackageAudit,"没有审核套餐");
        // 2 获取审核中，高亮点集合
        List<String> highLightedActivities=Collections.emptyList();
        String processDefinitionKey=null;
        if(busCarPackageAudit.getStatus()==PackageAuditEnum.AUDITING.ordinal()){
            // 获取流程实例
            ProcessInstance instance = runtimeService.createProcessInstanceQuery()
                    .processInstanceId(busCarPackageAudit.getInstanceId())
                    .singleResult();
            processDefinitionKey=instance.getProcessDefinitionKey();
            // 获取高亮信息
            highLightedActivities=runtimeService
                    .getActiveActivityIds(busCarPackageAudit.getInstanceId());

        }else{
            // 3 不是审核，从历史获取流程定义key
            HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery()
                    .processInstanceId(busCarPackageAudit.getInstanceId())
                    .singleResult();
            Assert.notNull(historicProcessInstance,"历史上不存在此流程实例");
            processDefinitionKey=historicProcessInstance.getProcessDefinitionKey();
        }
        //Query return 5 results instead of max 1
        // 4 通过流程定义相关信息流程定义key，查询流程定义，bpmnModel
//        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
//                .processDefinitionKey(processDefinitionKey)
//                .orderByProcessDefinitionVersion().desc().list().get(0);

        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
                .processDefinitionKey(processDefinitionKey)
                .latestVersion().singleResult();
        Assert.notNull(processDefinition,"查询不到流程定义");
        BpmnModel bpmnModel = repositoryService
                .getBpmnModel(processDefinition.getId());
        // 5 绘制流程进度
        DefaultProcessDiagramGenerator defaultProcessDiagramGenerator=
                new DefaultProcessDiagramGenerator();
        return defaultProcessDiagramGenerator.generateDiagram(
                bpmnModel,
                highLightedActivities,
                Collections.emptyList(),
                "宋体",
                "宋体",
                "宋体"
        );
    }

    @Override
    public List<BusCarPackageAudit> doneQuery(BusCarPackageAuditVo auditVo) {
        //1 获取服务类型流程定义相关信息，获取流程定义key
        BusBpmnInfo busBpmnInfo = busBpmnInfoMapper.getByBpmnType(0);
        Assert.notNull(busBpmnInfo,"请上传流程定义文件");
        //2 查询历史任务表（通过用户id和流程定义key）：hi-taskinst,最终目标获取流程实例ids
        String userId = SecurityUtils.getUserId().toString();
        List<HistoricTaskInstance> historicTaskInstances = historyService
                .createHistoricTaskInstanceQuery()
                .processDefinitionKey(busBpmnInfo.getProcessDefinitionKey())
                .taskAssignee(userId)
                .list();
        Set<String> processIds=historicTaskInstances.stream()
                .map(taskInstance -> taskInstance.getProcessInstanceId())
                .collect(Collectors.toSet());
        Assert.notEmpty(processIds,"没有流程实例id");
        //3 通过流程实例ids，查询历史流程实例表：hi-procinst,最终目标获取businessKeys(服务项id)
        List<HistoricProcessInstance> processInstances = historyService
                .createHistoricProcessInstanceQuery()
                .processDefinitionKey(busBpmnInfo.getProcessDefinitionKey())
                .processInstanceIds(processIds).list();
        //4 通过businessKeys获取历史审核套餐信息（非审核中，这样出现小黑审批通过，
        List<String> businessKeys = processInstances.stream()
                .map(historicProcessInstance -> historicProcessInstance.getBusinessKey())
                .collect(Collectors.toList());
        // 但是还要小白审批时候，小黑此时在我的已办中是查不到）
        PageUtils.startPage();
        List<BusCarPackageAudit> busCarPackageAudits = busCarPackageAuditMapper
                .selectBusCarPackageDoneListByBusinessKeys(businessKeys);
        return busCarPackageAudits;
    }

    private void updateState(BusCarPackageAudit busCarPackageAudit,
                             BusCarPackageAudit audit,
                             BusServiceItem serviceItem,
                             PackageAuditEnum pass,
                             AuditEnum pass2) {
        audit.setId(busCarPackageAudit.getId());
        //审核套餐审核通过
        audit.setStatus(pass.ordinal());
        busCarPackageAuditMapper.updateBusCarPackageAudit(audit);
        //服务单项审核审核通过
        serviceItem.setId(busCarPackageAudit.getServiceItemId());
        serviceItem.setAuditStatus(pass2.ordinal());
        busServiceItemMapper.updateBusServiceItem(serviceItem);
    }
}
